package com.kaochong.xcx.service.impl;

import com.google.common.collect.Lists;

import com.kaochong.common.util.BeanConvertUtil;
import com.kaochong.common.util.KaoChongStringUtils;
import com.kaochong.xcx.cache.TokenCache;
import com.kaochong.xcx.cache.UserInfoCache;
import com.kaochong.xcx.cache.UserMistakesCache;
import com.kaochong.xcx.cache.UserWordCache;
import com.kaochong.xcx.cache.WordBookCache;
import com.kaochong.xcx.common.constant.CommonConstant;
import com.kaochong.xcx.dao.UserInfoMapper;
import com.kaochong.xcx.dao.UserMapper;
import com.kaochong.xcx.entity.User;
import com.kaochong.xcx.entity.UserInfo;
import com.kaochong.xcx.entity.UserMistakes;
import com.kaochong.xcx.entity.WordBook;
import com.kaochong.xcx.enums.FinishStatus;
import com.kaochong.xcx.enums.ResultEnum;
import com.kaochong.xcx.enums.StageStatus;
import com.kaochong.xcx.enums.SubscriptionStatus;
import com.kaochong.xcx.exception.KaoChongException;
import com.kaochong.xcx.pojo.cache.WordModel;
import com.kaochong.xcx.pojo.dto.TargetPeopleDTO;
import com.kaochong.xcx.pojo.vo.WordBookVO;
import com.kaochong.xcx.service.PrizesService;
import com.kaochong.xcx.service.ShareService;
import com.kaochong.xcx.service.UserMistakesService;
import com.kaochong.xcx.service.UserService;
import com.kaochong.xcx.service.UserStageWordsService;
import com.kaochong.xcx.service.WordBookService;
import com.kaochong.xcx.utils.CalculateUtil;
import com.kaochong.xcx.utils.DateUtil;
import com.kaochong.xcx.web.aspect.CurrentUser;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import lombok.extern.slf4j.Slf4j;

/**
 * @author han
 * @date 2018-05-01 13:20
 */
@Service
@Slf4j
public class UserServiceImpl implements UserService {
	
	@Autowired
	UserMapper userMapper;
	
	@Autowired
	UserInfoMapper userInfoMapper;
	
	@Autowired
	UserStageWordsService userStageWordsService;
	
	@Autowired
	UserWordCache userWordCache;
	
	@Autowired
	TokenCache tokenCache;
	
	@Autowired
	UserInfoCache userInfoCache;
	
	@Autowired
	UserMistakesCache userMistakesCache;
	
	@Autowired
	UserMistakesService userMistakesService;
	
	@Autowired
	ShareService shareService;
	
	@Autowired
	WordBookCache wordBookCache;

	@Autowired
	PrizesService prizesService;
	
	/**
	 * 默认连续学习天数
	 */
	private final static Integer DEFAULT_KEEP_DAY = 0;
	
	/**
	 * 默认当前需要学习的阶段
	 */
	private final static Integer DEFAULT_CURR_STAGE = 1;
	
	@Override
	@Transactional(rollbackFor = Exception.class)
	public Map<String, Object> login(String openId, String nickname, String portrait ,String fromWhere) {
		// 1.openId查询用户
		User user = userMapper.findByOpenId(openId);
		boolean isNewUser = false;
		if (user == null) {
			isNewUser = true;
			user = register(openId, nickname, portrait,fromWhere);
		}
		
		CurrentUser currentUser;
		
		if (null != user.getTargetMarkId()) {
			// 2.获取用户信息
			UserInfo userInfo = userInfoMapper.selectByPrimaryKey(user.getTargetMarkId());
			
			// 3.封装用户信息返回
			currentUser = BeanConvertUtil.convert(userInfo, CurrentUser.class);
			currentUser.setId(user.getId());
			currentUser.setNickname(user.getNickname());
			currentUser.setPortrait(user.getPortrait());
			currentUser.setOpenId(user.getOpenId());
		} else {
			currentUser = new CurrentUser();
			currentUser.setId(user.getId());
			currentUser.setNickname(user.getNickname());
			currentUser.setPortrait(user.getPortrait());
			currentUser.setOpenId(user.getOpenId());
		}
		Map<String, Object> map = new HashMap<>();
		map.put("currentUser", currentUser);
		map.put("isNewUser", isNewUser);
		return map;
	}
	
	@Override
	@Transactional(rollbackFor = Exception.class)
	public String updateUserTarget(CurrentUser currentUser, Integer target) {
		WordBook wordBook = wordBookService.getWordBook(target);
		Integer bookNo = wordBook.getTarget();
		Long userId = currentUser.getId();
		
		// 修改用户培养目标
		UserInfo userInfo = userInfoMapper.findByUserIdAndTarget(userId, bookNo);
		Date now = new Date();
		String targetMarkId;
		User user = userMapper.selectByPrimaryKey(userId);
		if (null == userInfo) {
			targetMarkId = KaoChongStringUtils.generateUUID();
			user.setTargetMarkId(targetMarkId);
			user.setUpdateTime(now);
			userMapper.updateByPrimaryKey(user);
			
			// 用户信息表添加记录
			userInfo = new UserInfo();
			userInfo.setUserId(userId);
			userInfo.setTarget(bookNo);
			userInfo.setTargetMarkId(targetMarkId);
			userInfo.setStudyWordsNum(0);
			userInfo.setSubscriptionStatus(SubscriptionStatus.SUBSCRIPTION.getCode());
			userInfo.setFinishStatus(FinishStatus.DEFAULT.getCode());
			userInfo.setLastStudyTime(now);
			userInfo.setKeepDay(DEFAULT_KEEP_DAY);
			userInfo.setCurrStage(DEFAULT_CURR_STAGE);
			userInfo.setCurrStageStatus(StageStatus.DEFAULT.getCode());
			userInfo.setTestResult(null);
			userInfo.setCreateTime(now);
			userInfo.setBeginTime(now);
			userInfo.setUpdateTime(now);
			userInfoMapper.insert(userInfo);
		} else {
			targetMarkId = userInfo.getTargetMarkId();
			user.setTargetMarkId(targetMarkId);
			user.setUpdateTime(now);
			userMapper.updateByPrimaryKey(user);
			
			String markId = currentUser.getTargetMarkId();
			Integer stage = currentUser.getCurrStage();
			
			// 删除用户当前状态已学数据
			//userInfoCache.deleteAll(userId, markId, stage);
			// 删除redis用户阶段
			userWordCache.delAll(userId, stage, markId);
			// 删除redis用户错题
			userMistakesCache.del(userId, markId);
		}
		
		// 更新redis用户培养目标
		CurrentUser redisUser = BeanConvertUtil.convert(userInfo, currentUser);
		tokenCache.setToken(currentUser.getToken(), redisUser);
		return targetMarkId;
	}
	
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void resetUserTarget(CurrentUser user, Integer targetCode) {
		// 查询用户信息
		Long userId = user.getId();
		WordBook wordBook = wordBookService.getWordBook(targetCode);
		Integer target = wordBook.getTarget();
		UserInfo userInfo = userInfoMapper.findByUserIdAndTarget(userId, target);
		
		if (null == userInfo) {
			Date now = new Date();
			String markId = KaoChongStringUtils.generateUUID();
			userInfo = new UserInfo();
			userInfo.setUserId(userId);
			userInfo.setTarget(target);
			userInfo.setTargetMarkId(markId);
			userInfo.setStudyWordsNum(0);
			userInfo.setSubscriptionStatus(SubscriptionStatus.SUBSCRIPTION.getCode());
			userInfo.setFinishStatus(FinishStatus.DEFAULT.getCode());
			userInfo.setLastStudyTime(now);
			userInfo.setKeepDay(DEFAULT_KEEP_DAY);
			userInfo.setCurrStage(DEFAULT_CURR_STAGE);
			userInfo.setCurrStageStatus(StageStatus.DEFAULT.getCode());
			userInfo.setTestResult(null);
			userInfo.setCreateTime(now);
			userInfo.setBeginTime(now);
			userInfo.setUpdateTime(now);
			userInfoMapper.insert(userInfo);
		} else {
			String targetMarkId = userInfo.getTargetMarkId();
			Integer stage = userInfo.getCurrStage();
			
			Date now = new Date();
			userInfo.setTarget(target);
			userInfo.setTargetMarkId(targetMarkId);
			userInfo.setStudyWordsNum(0);
			userInfo.setFinishStatus(FinishStatus.DEFAULT.getCode());
			userInfo.setLastStudyTime(now);
			userInfo.setKeepDay(DEFAULT_KEEP_DAY);
			userInfo.setCurrStage(DEFAULT_CURR_STAGE);
			userInfo.setCurrStageStatus(StageStatus.DEFAULT.getCode());
			userInfo.setTestResult(null);
			userInfo.setBeginTime(now);
			userInfo.setUpdateTime(now);
			userInfoMapper.updateByPrimaryKey(userInfo);
			
			// 删除用户阶段
			userStageWordsService.deleteUserStage(userId, targetMarkId);
			// 删除用户错题
			userMistakesService.deleteUserMistakes(userId, targetMarkId, target);
			// 删除用户已学数据
			userInfoCache.deleteAll(userId, targetMarkId, stage);
			// 删除redis用户阶段
			userWordCache.delAll(userId, stage, targetMarkId);
			// 删除redis用户错题
			userMistakesCache.del(userId, targetMarkId);
			// 生成今天的题库/重置题库
			//userStageWordsService.reset(user.getId(), target, targetMarkId);
			
			User one = userMapper.selectByPrimaryKey(userId);
			if (targetMarkId.equals(one.getTargetMarkId())) {
				// 更新redis用户培养目标
				CurrentUser currentUser = BeanConvertUtil.convert(userInfo, user);
				tokenCache.setToken(user.getToken(), currentUser);
			}
		}
	}
	
	@Override
	@Transactional(rollbackFor = Exception.class)
	public Map<String, Object> getUserInfoV1(CurrentUser user) {
		Map<String, Object> result = new HashMap<>();
		Map<String, Object> userMap = new HashMap<>();

		/**当前是否有抽奖活动在进行,控制前端抽奖按钮是否显示begin**/
		Integer prizeSate = prizesService.getPrizeState();
		result.put("prizeState", prizeSate);
		/***********************end*********************/
		
		Long userId = user.getId();
		// 用户培养目标4/6级别
		Integer target = user.getTarget();
		if (null == target) {
			userMap.put("status", 0);
			userMap.put("nickname", user.getNickname());
			userMap.put("openId", user.getOpenId());
			result.put("userInfo", userMap);
			return result;
		}
		
		// 此次培养唯一标识
		String targetMarkId = user.getTargetMarkId();
		Integer currStage = user.getCurrStage();
		List<WordModel> todayWords = todayWords(user);
		
		// 培养目标下单词总数
		WordBook wordBook = wordBookService.getWordBook(target);
		Integer totalStage = wordBook.getTotalStage();
		
		// 针对隔夜答题情况做的此判断
		CurrentUser afterUser = tokenCache.getToken(user.getToken());
		
		userMap.put("target", afterUser.getTarget());
		userMap.put("stage", afterUser.getCurrStage());
		userMap.put("surplus", todayWords.size());
		
		// 剩余天数
		String key = userInfoCache.genKey(userId, targetMarkId, currStage);
		if (StageStatus.FINISHED.getCode().equals(afterUser.getCurrStageStatus())) {
			userMap.put("surplusDay", totalStage-afterUser.getCurrStage());
			key = userInfoCache.genKey(userId, targetMarkId, afterUser.getCurrStage());
		} else {
			if (!currStage.equals(afterUser.getCurrStage())) {
				key = userInfoCache.genKey(userId, targetMarkId, afterUser.getCurrStage());
				userMap.put("surplusDay", totalStage - currStage);
			} else {
				userMap.put("surplusDay", totalStage - afterUser.getCurrStage() + 1);
			}
		}
		
		if (totalStage - afterUser.getCurrStage() <= 0) {
			userMap.put("isFinalTest", true);
		} else {
			userMap.put("isFinalTest", false);
		}
		
		// 连续学习天数
		userMap.put("keepDay", afterUser.getKeepDay());
		// 已学单词数
		userMap.put("studyWordsNum", afterUser.getStudyWordsNum());
		// 今日单词
		userMap.put("todayWordsSum", userInfoCache.hGetTodayWordNum(key));
		if (afterUser.getCurrStage() >= totalStage) {
			Integer finalTest = userInfoCache.hGetFinalTest(key);
			userMap.put("finalTest", finalTest);
		}
		
		Date beginTime = afterUser.getBeginTime();
		Date updateTime = afterUser.getUpdateTime();
		if (null == updateTime) {
			UserInfo one = userInfoMapper.selectByPrimaryKey(targetMarkId);
			Date updateTime1 = one.getUpdateTime();
			afterUser.setUpdateTime(updateTime1);
			tokenCache.setToken(afterUser.getToken(), afterUser);
			updateTime = updateTime1;
		}
		if (null == beginTime) {
			beginTime = new Date();
		}
		int studyDays = DateUtil.daysBetween(beginTime, updateTime);
		userMap.put("studyDays", studyDays + 1);
		userMap.put("stageStatus", afterUser.getCurrStageStatus());
		
		if (FinishStatus.FINISHED.getCode().equals(afterUser.getFinishStatus())) {
			userMap.put("status", 3);
		} else {
			Integer stageStatus = afterUser.getCurrStageStatus();
			if (StageStatus.FINISHED.getCode().equals(stageStatus)) {
				userMap.put("status", 2);
			} else {
				userMap.put("status", 1);
			}
		}
		
		userMap.put("nickname", user.getNickname());
		userMap.put("openId", user.getOpenId());
		
		result.put("userInfo", userMap);
		result.put("wordbook", BeanConvertUtil.convert(wordBook, WordBookVO.class));


		return result;
	}
	
	@Autowired
	WordBookService wordBookService;
	
	@Override
	public List<Map<String, Object>> studySchedule(Long userId) {
		List<UserInfo> list = userInfoMapper.findByUserId(userId);
		List<WordBookVO> books = wordBookService.getPutawayList();
		
		List<Map<String, Object>> result = Lists.newArrayList();
		
		for (UserInfo userInfo : list) {
			for (WordBookVO book : books) {
				if (book.getTarget().equals(userInfo.getTarget())) {
					Map<String, Object> map = new HashMap<>();
					Integer stu = userInfo.getStudyWordsNum();
					Integer tot = book.getWordsNum();
					
					Integer rate = CalculateUtil.divideRoundDown(stu, tot);
					map.put("target", userInfo.getTarget());
					map.put("schedule", rate);
					result.add(map);
				}
			}
		}
		return result;
	}
	
	@Override
	public User findByOpenId(String openId) {
		return userMapper.findByOpenId(openId);
	}
	
	@Override
	public UserInfo findUserInfo(Long userId, Integer target) {
		return userInfoMapper.findByUserIdAndTarget(userId, target);
	}
	
	@Override
	public List<TargetPeopleDTO> findEveryTargetCount() {
		List<TargetPeopleDTO> result = wordBookCache.getEveryTargetCount();
		
		if (result.isEmpty()) {
			result = userInfoMapper.countEveryTargetNum();
			for (TargetPeopleDTO dto : result) {
				dto.setCount(dto.getCount() * CommonConstant.EVERY_WORDBOOK_MULTIPLE);
			}
			wordBookCache.saveEveryTargetCount(result);
		}
		return result;
	}
	
	@Override
	public List<User> findAllLuckyUser(String prizeDate) {
		return userMapper.findAllLuckyUser(prizeDate);
	}
	
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void openNext(CurrentUser user) {
		// 已完成所有任务
		if (FinishStatus.FINISHED.getCode().equals(user.getFinishStatus())) {
			throw new KaoChongException(ResultEnum.COMPLETE_ALL_PROGRESS);
		}
		
		Date yesterday = DateUtil.getYesterday();
		user.setLastStudyTime(yesterday);
		
		tokenCache.setToken(user.getToken(), user);
		
		UserInfo one = new UserInfo();
		one.setTargetMarkId(user.getTargetMarkId());
		one.setLastStudyTime(yesterday);
		one.setUpdateTime(new Date());
		userInfoMapper.updateByPrimaryKeySelective(one);
		
		// 重置好友助力
		shareService.resetFriendHelp(user.getOpenId(), user.getTarget());
	}
	
	/**
	 * 获取用户今天的所有问题
	 * @param user
	 * @return
	 */
	@Override
	public List<WordModel> todayWords(CurrentUser user) {
		Integer currStage = user.getCurrStage();
		Integer currStageStatus = user.getCurrStageStatus();
		Date lastStudyTime = user.getLastStudyTime();
		int diffDays = DateUtil.daysBetween(lastStudyTime, new Date());
		List<WordModel> userStageWord = new ArrayList<>();
		// 跟上次时间比较 是否大于一天
		if (diffDays > 0) {
				List<UserMistakes> mistakes = userMistakesService.findAllMistakes(user.getId(), user.getTargetMarkId(), user.getTarget());
				userMistakesCache.del(user.getId(), user.getTargetMarkId());
				userMistakesCache.hPutAllMistakes(user.getId(), user.getTargetMarkId(), mistakes);
				userWordCache.del(user.getId(), currStage, user.getTargetMarkId());
				// 用户当前阶段是否完成
				// 完成则查下一阶段
				if (StageStatus.FINISHED.getCode().equals(currStageStatus)) {
					currStage = currStage + 1;
					user.setCurrStage(currStage);
				}
				// 否则查当前阶段
				userStageWord = userStageWordsService.getUserStageWord(user);
		} else {
			if(StageStatus.FINISHED.getCode().equals(currStageStatus)) {
				return userStageWord;
			} else {
				userStageWord = userStageWordsService.getUserStageWord(user);
			}
		}
		return userStageWord;
	}
	
	/**
	 * 用户注册
	 * @param openId
	 * @param nickname
	 * @param portrait
	 * @return
	 */
	private User register(String openId, String nickname, String portrait , String fromWhere) {
		Date now = new Date();
		User user = new User();
		user.setOpenId(openId);
		user.setNickname(nickname);
		user.setPortrait(portrait);
		user.setFromWhere(fromWhere);
		user.setCreateTime(now);
		user.setUpdateTime(now);
		userMapper.insertUser(user);
		return user;
	}
}
